﻿// Inner Fire 游戏引擎库
// AnimatorChannel - 通用播放接口（播放输出）
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层(4)
// 这东西其实应该叫PlayableChannel的，但为了和Unity统一（其实也没统一什么）
// 就把他叫成Output了。但是和Unity的Playable的Output完全不是一回事。
// 这东西更像是Animator中的一个层。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-04-30

#pragma once

#include "playable.h"
#include <EASTL/array.h>
#include <game/animation/snapshot.h>
#include <static_string.h>

namespace ifire::game {
class Animator;
class AnimationClip;
class AnimationBlend;
class Armature;

// 当前Channel的状态
enum class AnimatorChannelState {
  Idle, // 闲置状态，没有播放任何动画
  Play, // 播放当前的动画
  Transition,  // 将当前动画与下一个动画混合
};

class AnimatorChannel {
public:
  AnimatorChannel(
      Animator* animator, ikit::sstr channel_name, int channel_index);
  AnimatorChannel(const AnimatorChannel& lhs) = delete;
  AnimatorChannel& operator=(const AnimatorChannel& lhs) = delete;
  ~AnimatorChannel() = default;

  // 通过一个Play指令设置当前的播放项目。返回该指令影响的Playable
  void Play(const Playable& p, float transition_time = 0.0f);

  // 清除当前的动画帧
  void Clear();

  // 执行此通道的演算
  void Play();

  // 执行一个Playable的演算
  void Execute(Playable& playable);
  // 执行单个CLIP的演算
  void ExecuteSlot(AnimationClip* clip, const Playable& playable,
      int slot_index, float weight);

  // 得到骨架
  Armature* GetArmature();

  // 获取用于Current的指定Slot位置
  Snapshot& GetSlot(int slot);
  // 获得最终的Mix
  Snapshot& GetMix();

public:
  // 此通道的名称
  ikit::sstr name;
  // 此通道的索引ID
  int index;
  // 当前正在播放的项目
  Playable current;
  // 下一个要播放的项目
  Playable next;
  // 当前的状态
  AnimatorChannelState state;

private:
  // 对Transition的状态进行混合
  void MixTransition();
  // 对SnapShot进行混合（需要对OffsetIndex进行加算）
  void MixSlot(int a, int b, int to_c);

  // 变换所需要的时间
  float transition_time_;
  // 当前的变换进度
  float transition_tick_;
  // 用于控制slot_index的项目。当播放当前的时候为0,next的时候为1
  int slot_offset_;

  // 此通道所属的Animator
  Animator* animator_;
  // 用于混合的项目，Current使用
  std::unique_ptr<Snapshots> snapshots_;
};

} // namespace ifire::game